let exchangeDao = require('../dao/exchangeDao');
let exchangeConfigDao = require('../dao/exchangeConfigDao');
let payAcctDao = require('../dao/payAcctDao');
let userDao = require('../dao/userDao');
let busiConst = require('../const/busiConst');
let stringUtil = require('../util/stringUtil');
let dateUtil = require('../util/dateUtil');
let idUtil = require('../util/idUtil');
let conf = require('../config/config');
let redis = require('../dao/redis');
let mysqlPool = require('../dao/MySQLPool');
let payService = require('../service/PayService');

let assert = require('assert');

let exchangeService = module.exports;

/**
 * 查询兑换记录
 * @param uid
 * @param page
 * @returns {Promise<void>}
 */
exchangeService.records = async function (uid, page) {
    let cacheKey = "ex:record:" + uid + ":" + page;
    let cache = await redis.get(cacheKey);
    if (!cache){
        let count = await exchangeDao.getRecordCount(uid);
        let records = await exchangeDao.getRecordByPage(uid, page, 10);

        cache = {count: count, records: records};

        await redis.set(cacheKey, cache, 60);
    }

    return cache;
};

/**
 * 查询提现记录
 * @param cond
 *      cond.uid
 *      cond.status
 *      cond.type
 *      cond.startTime
 *      cond.endTime
 *      cond.page
 *      cond.count
 * @returns {Promise<{cnt: number, data: Array}>}
 */
exchangeService.queryPageByCond = async function(cond){
    let cnt = await exchangeDao.queryPageCntByCond(cond);
    if (cnt <= 0){
        return {cnt:0, data: []};
    }

    let res = await exchangeDao.queryPageByCond(cond);
    return {cnt:cnt, data: res};
};


exchangeService.save = async function (record) {
    let res = await exchangeDao.save(record);
    return res;
};

/**
 * 接受审批
 * @param record
 *      record.flowNo {String}
 *      record.operator {int}
 *      record.payChannel {String}
 * @returns {Promise<*>}
 */
exchangeService.auditAccept = async function(record){
    let lockKey = "ex:audit:" + record.flowNo;
    let isSucc = await redis.lock(lockKey, 1, 5);
    if (!isSucc){
        console.logw("audit limit:", lockKey, record);
        return null;
    }

    let r = await exchangeDao.getRecordByFlowNoAndStatus(record.flowNo, 0);
    assert(r, "get ex record res is null");
    assert(r.status === 0, "订单状态异常");

    await mysqlPool.doWithTx(async function (conn) {
        let res = await userDao.releaseFreezeCoinWithTx(conn, r.uid, r.ex_amt);
        assert(res > 0, "release freeze coin err: res <= 0");
        let res1 =  await exchangeDao.updateStatusWithTx(conn, {status: 1, flowNo:record.flowNo, operator:record.operator});
        assert(res1 > 0, "update ex status err: res1 <= 0");
        await payService.getService(record.payChannel).withdraw(r.flow_no, "accept", record.operator);
    });
};

/**
 * 拒绝审批
 * @param record
 *      record.flowNo
 *      record.operator
 *      record.remark
 * @returns {Promise<*>}
 */
exchangeService.auditRefuse = async function(record){
    let lockKey = "ex:audit:" + record.flowNo;
    let isSucc = await redis.lock(lockKey, 1, 5);
    if (!isSucc){
        console.logw("audit limit:", lockKey, record);
        return null;
    }

    let r = await exchangeDao.getRecordByFlowNoAndStatus(record.flowNo, 0);
    assert(r, "get ex record res is null");
    assert(r.status === 0, "订单状态异常");

    await mysqlPool.doWithTx(async function (conn) {
        let res = await userDao.restoreCoinFromFreezeWithTx(conn, r.uid + "", r.ex_amt);
        assert(res > 0, "release restore coin err: res <= 0");
        let res1 =  await exchangeDao.updateStatusWithTx(conn,
            {status:-1, flowNo:record.flowNo, operator:record.operator, remark:record.remark});
        assert(res1 > 0, "update ex status err: res1 <= 0");
    });

    return 1;
};

/**
 * 发起兑换
 * @param exDto
 *      exDto.uid
 *      exDto.type
 *      exDto.exAmt
 * @returns {Promise<*>}
 */
exchangeService.exchange = async function (exDto) {
    let lockKey = "ex:exchange:" + exDto.uid + ":" + exDto.type;
    let isSucc = await redis.lock(lockKey, 1, 5);
    if (!isSucc){
        console.logw("exchange limit:", lockKey, exDto);
        return null;
    }

    let payAcct = await payAcctDao.get({uid: exDto.uid, type: exDto.type});
    if (!payAcct) {
        console.logw("no this pay acct:", exDto);
        return null;
    }

    let exConfig = await exchangeConfigDao.getConfig(exDto.type);
    if (!exConfig){
        console.logw("no this ex config:", exDto);
        return null;
    }

    let exAmt = parseFloat(exDto.exAmt).toFixed(2);
    let exFee = parseFloat(exAmt * exConfig.rate / 100).toFixed(2);
    let realExAmt = exAmt - exFee;

    let flowNo = busiConst.TYPE_EXCHANGE_FLOW_NO + conf.machineNo + dateUtil.dateFormat("yyyyMMddhhmmss")
        +  stringUtil.padZeroSix(idUtil.nextSix());
    let record = {
        uid: exDto.uid,
        flowNo: flowNo,
        exAmt: exAmt,
        type: exDto.type,
        exNo: payAcct.acct_no,
        realExAmt: realExAmt,
        exFee: exFee,
        exFeeRate: exConfig.rate
    };

    await mysqlPool.doWithTx(async function (conn) {
        let leftCoin = await userDao.getCoinWithTx(conn, exDto.uid);
        assert(leftCoin >= exAmt, "leftCoin < exAmt");
        let res =  await exchangeDao.saveWithTx(conn, record);
        assert(res > 0, "save ex record err: res <= 0");
        let res1 = await userDao.freezeCoinWithTx(conn, exDto.uid, exAmt);
        assert(res1 > 0, "dec user coin err: res1 <= 0");
    });

    let leftCoin = await userDao.getCoin(exDto.uid);
    return leftCoin;
};